//=========================================================
// File			- f32.h
// Author		- Jesse Lampert
// Created	- 04/18/06
//=========================================================

#ifndef __F32_H
#define __F32_H

//=== Includes ============================================
#include "stdTypes.h"
#include "apiBridge.h"

//=== Constants ===========================================
#define F32_BITS	(10)	// bits of decimal in f32 type

//=== Classes, Structures and Unions ======================
//=========================================================
// Class		- f32
// Purpose	- fixed point number
//=========================================================
class f32
{
	public:
		int32								Value;															// internal fixed point value

	public:
		inline f32( void ) { }

		// copy constructors
		inline f32( const f32 & value ) { Value = value.Value; }
		explicit inline f32( int32 value ) { Value = value; }
		explicit inline f32( int16 value ) { Value = ( (int32)value << F32_BITS ); }
		explicit inline f32( int8 value ) { Value = ( (int32)value << F32_BITS ); }
		
		// addition operators
		inline friend f32 operator+( f32 a, f32 b ) { return (f32)( a.Value + b.Value ); }
		inline friend f32 operator+( f32 a, int32 b ) { return (f32)( a.Value + b ); }
		inline friend f32 operator+( f32 a, int16 b ) { return (f32)( a.Value + ( b << F32_BITS ) ); }
		inline friend f32 operator+( f32 a, int8 b ) { return (f32)( a.Value + ( b << F32_BITS ) ); }
		inline friend f32 operator+( f32 a, uint16 b ) { return (f32)( a.Value + ( b << F32_BITS ) ); }
		inline friend f32 operator+( f32 a, uint8 b ) { return (f32)( a.Value + ( b << F32_BITS ) ); }
		inline friend f32 operator+( int32 a, f32 b ) { return (f32)( a + b.Value ); }
		inline friend f32 operator+( int16 a, f32 b ) { return (f32)( ( a << F32_BITS ) + b.Value ); }
		inline friend f32 operator+( int8 a, f32 b ) { return (f32)( ( a << F32_BITS ) + b.Value ); }
		inline friend f32 operator+( uint16 a, f32 b ) { return (f32)( ( a << F32_BITS ) + b.Value ); }
		inline friend f32 operator+( uint8 a, f32 b ) { return (f32)( ( a << F32_BITS ) + b.Value ); }
		
		// subtraction operators
		inline friend f32 operator-( f32 a, f32 b ) { return (f32)( a.Value - b.Value ); }
		inline friend f32 operator-( f32 a, int32 b ) { return (f32)( a.Value - b ); }
		inline friend f32 operator-( f32 a, int16 b ) { return (f32)( a.Value - ( b << F32_BITS ) ); }
		inline friend f32 operator-( f32 a, int8 b ) { return (f32)( a.Value - ( b << F32_BITS ) ); }
		inline friend f32 operator-( f32 a, uint16 b ) { return (f32)( a.Value - ( b << F32_BITS ) ); }
		inline friend f32 operator-( f32 a, uint8 b ) { return (f32)( a.Value - ( b << F32_BITS ) ); }
		inline friend f32 operator-( int32 a, f32 b ) { return (f32)( a - b.Value ); }
		inline friend f32 operator-( int16 a, f32 b ) { return (f32)( ( a << F32_BITS ) - b.Value ); }
		inline friend f32 operator-( int8 a, f32 b ) { return (f32)( ( a << F32_BITS ) - b.Value ); }
		inline friend f32 operator-( uint16 a, f32 b ) { return (f32)( ( a << F32_BITS ) - b.Value ); }
		inline friend f32 operator-( uint8 a, f32 b ) { return (f32)( ( a << F32_BITS ) - b.Value ); }
		
		// division operators
		inline friend f32 operator /( f32 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)b.Value ) );
		}
		inline friend f32 operator /( f32 a, int32 b )
		{
			ASSERT( b != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)b ) );
		}
		inline friend f32 operator /( f32 a, int16 b )
		{
			ASSERT( b != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)( b << F32_BITS ) ) );
		}
		inline friend f32 operator /( f32 a, int8 b )
		{
			ASSERT( b != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)( b << F32_BITS ) ) );
		}
		inline friend f32 operator /( f32 a, uint16 b )
		{
			ASSERT( b != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)( b << F32_BITS ) ) );
		}
		inline friend f32 operator /( f32 a, uint8 b )
		{
			ASSERT( b != 0 );
			return (f32)( (int32)( ( (int64)a.Value << F32_BITS ) / (int64)( b << F32_BITS ) ) );
		}
		inline friend f32 operator /( int32 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a << F32_BITS ) / (int64)b.Value ) );
		}
		inline friend f32 operator /( int16 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a << F32_BITS << F32_BITS ) / (int64)b.Value ) );
		}
		inline friend f32 operator /( int8 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a << F32_BITS << F32_BITS ) / (int64)b.Value ) );
		}
		inline friend f32 operator /( uint16 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a << F32_BITS << F32_BITS ) / (int64)b.Value ) );
		}
		inline friend f32 operator /( uint8 a, f32 b )
		{
			ASSERT( b.Value != 0 );
			return (f32)( (int32)( ( (int64)a << F32_BITS << F32_BITS ) / (int64)b.Value ) );
		}
		
		// multiplication operators
		inline friend f32 operator *( f32 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)b.Value ) >> F32_BITS ) );
		}
		inline friend f32 operator *( f32 a, int32 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)b ) >> F32_BITS ) );
		}
		inline friend f32 operator *( f32 a, int16 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)( b << F32_BITS ) ) >> F32_BITS ) );
		}
		inline friend f32 operator *( f32 a, int8 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)( b << F32_BITS ) ) >> F32_BITS ) );
		}
		inline friend f32 operator *( f32 a, uint16 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)( b << F32_BITS ) ) >> F32_BITS ) );
		}
		inline friend f32 operator *( f32 a, uint8 b )
		{
			return (f32)( (int32)( ( (int64)a.Value * (int64)( b << F32_BITS ) ) >> F32_BITS ) );
		}
		inline friend f32 operator *( int32 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)a * (int64)b.Value ) >> F32_BITS ) );
		}
		inline friend f32 operator *( int16 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)( a << F32_BITS ) * (int64)b.Value ) >> F32_BITS ) );
		}
		inline friend f32 operator *( int8 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)( a << F32_BITS ) * (int64)b.Value ) >> F32_BITS ) );
		}
		inline friend f32 operator *( uint16 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)( a << F32_BITS ) * (int64)b.Value ) >> F32_BITS ) );
		}
		inline friend f32 operator *( uint8 a, f32 b )
		{
			return (f32)( (int32)( ( (int64)( a << F32_BITS ) * (int64)b.Value ) >> F32_BITS ) );
		}
		
		// assignment operators
		inline const f32 & operator=( const f32 & value ) { Value = value.Value; return *this; }
		inline const f32 & operator=( const int32 & value ) { Value = value; return *this; }
		inline const f32 & operator=( const int16 & value ) { Value = (int32)( value << F32_BITS ); return *this; }
		inline const f32 & operator=( const int8 & value ) { Value = (int32)( value << F32_BITS ); return *this; }
		
		// equals operators
		inline friend boolean operator==( f32 a, f32 b ) { return a.Value == b.Value; }
		inline friend boolean operator==( f32 a, int32 b ) { return a.Value == b; }
		inline friend boolean operator==( f32 a, int16 b ) { return a.Value == ( b << F32_BITS ); }
		inline friend boolean operator==( f32 a, int8 b ) { return a.Value == ( b << F32_BITS ); }
		inline friend boolean operator==( int32 a, f32 b ) { return a == b.Value; }
		inline friend boolean operator==( int16 a, f32 b ) { return ( a << F32_BITS ) == b.Value; }
		inline friend boolean operator==( int8 a, f32 b ) { return ( a << F32_BITS ) == b.Value; }

		// not equals operators
		inline friend boolean operator!=( f32 a, f32 b ) { return a.Value != b.Value; }
		inline friend boolean operator!=( f32 a, int32 b ) { return a.Value != b; }
		inline friend boolean operator!=( f32 a, int16 b ) { return a.Value != ( b << F32_BITS ); }
		inline friend boolean operator!=( f32 a, int8 b ) { return a.Value != ( b << F32_BITS ); }
		inline friend boolean operator!=( int32 a, f32 b ) { return a != b.Value; }
		inline friend boolean operator!=( int16 a, f32 b ) { return ( a << F32_BITS ) != b.Value; }
		inline friend boolean operator!=( int8 a, f32 b ) { return ( a << F32_BITS ) != b.Value; }
		
		// greater operators
		inline friend boolean operator>( f32 a, f32 b ) { return a.Value > b.Value; }
		inline friend boolean operator>( f32 a, int32 b ) { return a.Value > b; }
		inline friend boolean operator>( f32 a, int16 b ) { return a.Value > ( b << F32_BITS ); }
		inline friend boolean operator>( f32 a, int8 b ) { return a.Value > ( b << F32_BITS ); }
		inline friend boolean operator>( int32 a, f32 b ) { return a > b.Value; }
		inline friend boolean operator>( int16 a, f32 b ) { return ( a << F32_BITS ) > b.Value; }
		inline friend boolean operator>( int8 a, f32 b ) { return ( a << F32_BITS ) > b.Value; }

		inline friend boolean operator>=( f32 a, f32 b ) { return a.Value >= b.Value; }
		inline friend boolean operator>=( f32 a, int32 b ) { return a.Value >= b; }
		inline friend boolean operator>=( f32 a, int16 b ) { return a.Value >= ( b << F32_BITS ); }
		inline friend boolean operator>=( f32 a, int8 b ) { return a.Value >= ( b << F32_BITS ); }
		inline friend boolean operator>=( int32 a, f32 b ) { return a >= b.Value; }
		inline friend boolean operator>=( int16 a, f32 b ) { return ( a << F32_BITS ) >= b.Value; }
		inline friend boolean operator>=( int8 a, f32 b ) { return ( a << F32_BITS ) >= b.Value; }

		// less operators
		inline friend boolean operator<( f32 a, f32 b ) { return a.Value < b.Value; }
		inline friend boolean operator<( f32 a, int32 b ) { return a.Value < b; }
		inline friend boolean operator<( f32 a, int16 b ) { return a.Value < ( b << F32_BITS ); }
		inline friend boolean operator<( f32 a, int8 b ) { return a.Value < ( b << F32_BITS ); }
		inline friend boolean operator<( int32 a, f32 b ) { return a < b.Value; }
		inline friend boolean operator<( int16 a, f32 b ) { return ( a << F32_BITS ) < b.Value; }
		inline friend boolean operator<( int8 a, f32 b ) { return ( a << F32_BITS ) < b.Value; }

		inline friend boolean operator<=( f32 a, f32 b ) { return a.Value <= b.Value; }
		inline friend boolean operator<=( f32 a, int32 b ) { return a.Value <= b; }
		inline friend boolean operator<=( f32 a, int16 b ) { return a.Value <= ( b << F32_BITS ); }
		inline friend boolean operator<=( f32 a, int8 b ) { return a.Value <= ( b << F32_BITS ); }
		inline friend boolean operator<=( int32 a, f32 b ) { return a <= b.Value; }
		inline friend boolean operator<=( int16 a, f32 b ) { return ( a << F32_BITS ) <= b.Value; }
		inline friend boolean operator<=( int8 a, f32 b ) { return ( a << F32_BITS ) <= b.Value; }

		inline boolean operator!( void ) const { return !Value; }

		// negation operator
		inline f32 operator -( void ) const { return (f32)-Value; }

		inline f32 Abs( void ) const { return Value < 0 ? (f32)-Value : (f32)Value; }

		// quick (but not so) quick operators
		inline const f32 & operator +=( f32 value ) { Value += value.Value; return *this; }
		inline const f32 & operator -=( f32 value ) { Value -= value.Value; return *this; }
		inline const f32 & operator /=( f32 value ) { ASSERT( value.Value != 0 ); *this = *this / value; return *this; }
		inline const f32 & operator *=( f32 value ) { *this = *this * value; return *this; }
	
		// pre/post inc operators
		inline const f32 & operator ++( void ) { Value += ( 1 << F32_BITS ); return *this; }
		inline const f32 & operator --( void ) { Value -= ( 1 << F32_BITS ); return *this; }
		
		// casting operator (to work with 'fixed' type)
		inline operator int32( void ) const { return Value; }

		// quick cast functions to native types
		inline int32 Int32( void ) const { return Value >> F32_BITS; }
		inline int16 Int16( void ) const { return (int16)( Value >> F32_BITS ); }
		inline int8 Int8( void ) const { return (int8)( Value >> F32_BITS ); }

		inline uint32 UInt32( void ) const { return (uint32)( Value >> F32_BITS ); }
		inline uint16 UInt16( void ) const { return (uint16)( Value >> F32_BITS ); }
		inline uint8 UInt8( void ) const { return (uint8)( Value >> F32_BITS ); }

		inline boolean SameSign( const f32 & value ) const { return Sign( ) == value.Sign( ); }
		inline int8	Sign( void ) const { return !Value ? 0 : ( Value < 0 ? -1 : 1 ); }
};

#endif // __F32_H